/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../impl/head.h"
#include "heart_acceptor.h"
#include "heart_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos_box
{
    ////////////////////////////////////////////////////////////////////////////////////
    // 

    static heart_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////

    heart_impl::heart_impl()
    {
        init_data();
    }

    heart_impl::~heart_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int heart_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int heart_impl::static_user_init()
    {
        int ret = 0;
        heart_acceptor::init_all();
        return ret;
    }

    int heart_impl::static_user_term()
    {
        int ret = 0;
        heart_acceptor::term_all();
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int heart_impl::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            m_pEvent = mgr::container()->xos()->event();
        }

        return nRet;
    }

    int heart_impl::init_data()
    {
        int ret = 0;
        m_iScanInterval = 1000;
        m_bQuit = false;
        m_pThread = 0;
        m_pEvent = 0;
        return ret;
    }

    int heart_impl::term()
    {
        int nRet = 0;

        if( m_pThread )
        {
            m_bQuit = true;
            m_pEvent->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        if( m_pEvent )
        {
            m_pEvent->release();
            m_pEvent = 0;
        }

        m_accept_list.put_back_to_pool();
        init_data();

        return nRet;
    }

    heart_acceptor::T* heart_impl::find( f_acceptor pAcceptor )
    {
        heart_acceptor::T* pFind = 0;

        for( ACCEPTOR_ITER i = m_accept_list.begin(); i != m_accept_list.end(); ++i )
        {
            heart_acceptor::T* p = *i;
            if( p->m_pAcceptor == pAcceptor )
            {
                pFind = p;
                break;
            }
        }

        return pFind;
    }

    void * heart_impl::thread( void* lpData )
    {
        using namespace std;

        heart_impl& obj = *(heart_impl*)lpData;

        int64_t i64_deffrence = 0;
        int32_t i32_interval = 0;
        xos::i_time* pBegin = 0;
        xos::i_time* pEnd = 0;
        bool bFirst = true;

        {
            pBegin = mgr::container()->xos()->tm();
            pEnd = mgr::container()->xos()->tm();
        }

        while( !obj.m_bQuit )
        {
            i32_interval = obj.m_iScanInterval - (int32_t)i64_deffrence;
            if( i32_interval < 0 )
            {
                i32_interval = 0;
            }
            if( bFirst )
            {
                pBegin->get_time();
                bFirst = false;
            }
            obj.m_pEvent->wait( i32_interval );
            if( !obj.m_bQuit )
            {
                obj.scan();
            }
            pEnd->get_time();
            pEnd->diffrent( pBegin, &i64_deffrence );
            i64_deffrence -= i32_interval;
            pBegin->get_time();
        }

        {
            xos_stl::release_interface( pBegin );
            xos_stl::release_interface( pEnd );
        }

        return 0;
    }

    int heart_impl::scan()
    {
        int nRet = 0;

        m_lock.lock();

        for( ACCEPTOR_ITER i = m_accept_list.begin(); i != m_accept_list.end(); ++i )
        {
            heart_acceptor* p = *i;
            p->m_iCurTime += m_iScanInterval;
            if( p->m_iCurTime >= p->m_iInterval )
            {
                p->m_iCurTime = 0;
                p->m_pAcceptor();
            }
        }

        m_lock.un_lock();

        return nRet;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // set heart check interval : ms
    // 
    int heart_impl::set_sys_check_interval( int32_t iSysCheckIntervalMS )
    {
        int nRet = 0;
        m_iScanInterval = iSysCheckIntervalMS;
        return nRet;
    }

    // 
    // add acceptor : ms
    // 
    int heart_impl::add_acceptor( f_acceptor pAcceptor, int32_t iHeartIntervalMS )
    {
        int nRet = 0;

        heart_acceptor::T* pFind = 0;

        if( !pAcceptor )
        {
            return 1;
        }

        m_lock.lock();

        pFind = find( pAcceptor );

        if( !pFind )
        {
            heart_acceptor* pH = 0;
            nRet = xos_stl::init_pool_item( pH );
            if( 0 == nRet )
            {
                pFind = static_cast<heart_acceptor::T*>(pH);
                m_accept_list.push_back( pFind );
            }
        }

        if( pFind )
        {
            pFind->m_iInterval = iHeartIntervalMS;
            pFind->m_pAcceptor = pAcceptor;
        }

        m_lock.un_lock();

        return nRet;
    }

    // 
    // remove acceptor
    // 
    int heart_impl::rem_acceptor( f_acceptor pAcceptor )
    {
        int nRet = 0;

        heart_acceptor::T* pFind = 0;

        if( !pAcceptor )
        {
            return 1;
        }

        m_lock.lock();

        pFind = find( pAcceptor );

        if( pFind )
        {
            m_accept_list.remove( pFind );
            pFind->release();
            pFind = 0;
        }

        m_lock.un_lock();

        return nRet;
    }

    //
    // start/stop heart thread
    // 
    int heart_impl::start_heart_thread()
    {
        int ret = 0;

        if( (0 == ret) && m_pThread )
        {
            return 0;
        }

        if( 0 == ret )
        {
            m_pThread = mgr::container()->xos()->thread();
            ret = m_pThread->create( thread, this );
        }

        return ret;
    }

    int heart_impl::stop_heart_thread()
    {
        int ret = 0;

        if( m_pThread )
        {
            m_bQuit = true;
            m_pEvent->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
            m_bQuit = false;
        }

        return ret;
    }

} // xos
